using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Shared.Models;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace SumerCoreDevOps.ExecuteNodeApi.Services;

/// <summary>
/// 环境安装服务 - 自动安装缺失的构建环境
/// </summary>
public class EnvironmentInstaller
{
    private readonly ILogger<EnvironmentInstaller> _logger;
    private readonly EnvironmentDetector _detector;
    private readonly TaskExecutor? _taskExecutor;

    public EnvironmentInstaller(
        ILogger<EnvironmentInstaller> logger,
        EnvironmentDetector detector,
        TaskExecutor? taskExecutor = null)
    {
        _logger = logger;
        _detector = detector;
        _taskExecutor = taskExecutor;
    }

    /// <summary>
    /// 确保环境已安装（如果未安装则自动安装）
    /// </summary>
    public async Task<(bool Success, string Message)> EnsureEnvironmentAsync(
        EnvironmentRequirement requirement,
        long? taskId = null,
        long? stepId = null)
    {
        // 检查环境是否已安装
        var (isSatisfied, message) = await _detector.CheckRequirementAsync(requirement);

        if (isSatisfied)
        {
            _logger.LogInformation("环境已满足要求: {Name}", requirement.Name);
            await SendLogAsync(taskId, stepId, $"✓ 环境已满足要求: {requirement.Name}");
            return (true, "环境已安装");
        }

        _logger.LogWarning("环境不满足要求: {Message}", message);
        await SendLogAsync(taskId, stepId, $"⚠ {message}");

        // 自动安装
        await SendLogAsync(taskId, stepId, $"正在自动安装 {requirement.Name}...");

        var installResult = await InstallEnvironmentAsync(
            requirement.Name,
            requirement.RecommendedVersion ?? requirement.MinVersion,
            taskId,
            stepId);

        if (installResult.Success)
        {
            await SendLogAsync(taskId, stepId, $"✓ {requirement.Name} 安装成功");
            _logger.LogInformation("{Name} 安装成功", requirement.Name);

            // 重新检测以更新缓存
            await _detector.DetectEnvironmentAsync(requirement.Name);

            return (true, $"{requirement.Name} 已成功安装");
        }
        else
        {
            await SendLogAsync(taskId, stepId, $"✗ {requirement.Name} 安装失败: {installResult.Message}", "Error");
            _logger.LogError("{Name} 安装失败: {Error}", requirement.Name, installResult.Message);
            return (false, installResult.Message);
        }
    }

    /// <summary>
    /// 安装指定环境
    /// </summary>
    private async Task<(bool Success, string Message)> InstallEnvironmentAsync(
        string name,
        string? version,
        long? taskId,
        long? stepId)
    {
        var os = GetOperatingSystem();

        return name.ToLowerInvariant() switch
        {
            "dotnet" or ".net" => await InstallDotNetAsync(version, os, taskId, stepId),
            "java" => await InstallJavaAsync(version, os, taskId, stepId),
            "maven" or "mvn" => await InstallMavenAsync(version, os, taskId, stepId),
            "gradle" => await InstallGradleAsync(version, os, taskId, stepId),
            "node" or "nodejs" => await InstallNodeJsAsync(version, os, taskId, stepId),
            "python" => await InstallPythonAsync(version, os, taskId, stepId),
            "rust" or "cargo" => await InstallRustAsync(version, os, taskId, stepId),
            "go" or "golang" => await InstallGoAsync(version, os, taskId, stepId),
            _ => (false, $"不支持自动安装: {name}")
        };
    }

    #region 安装方法

    private async Task<(bool Success, string Message)> InstallDotNetAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        version ??= "9.0";

        if (os == "Linux")
        {
            // 使用官方安装脚本
            await SendLogAsync(taskId, stepId, "下载 .NET 安装脚本...");

            var downloadResult = await ExecuteCommandAsync(
                "curl",
                "-fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh",
                taskId,
                stepId);

            if (!downloadResult.Success)
            {
                return (false, "下载安装脚本失败");
            }

            await ExecuteCommandAsync("chmod", "+x /tmp/dotnet-install.sh", taskId, stepId);

            await SendLogAsync(taskId, stepId, $"安装 .NET {version}...");

            var installResult = await ExecuteCommandAsync(
                "/tmp/dotnet-install.sh",
                $"--channel {version}",
                taskId,
                stepId,
                timeoutMs: 300000); // 5分钟超时

            return installResult.Success
                ? (true, $".NET {version} 安装成功")
                : (false, "安装失败: " + installResult.Output);
        }
        else if (os == "Windows")
        {
            // 使用 winget 或 choco
            await SendLogAsync(taskId, stepId, $"尝试使用 winget 安装 .NET {version}...");

            var result = await ExecuteCommandAsync(
                "winget",
                $"install Microsoft.DotNet.SDK.{version.Split('.')[0]} --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, $".NET {version} 安装成功")
                : (false, "安装失败，请手动安装 .NET SDK");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallJavaAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        version ??= "17";

        if (os == "Linux")
        {
            await SendLogAsync(taskId, stepId, $"安装 OpenJDK {version}...");

            // 尝试使用系统包管理器
            var result = await ExecuteCommandAsync(
                "apt-get",
                $"install -y openjdk-{version}-jdk",
                taskId,
                stepId,
                timeoutMs: 300000);

            if (!result.Success)
            {
                // 尝试 yum
                result = await ExecuteCommandAsync(
                    "yum",
                    $"install -y java-{version}-openjdk-devel",
                    taskId,
                    stepId,
                    timeoutMs: 300000);
            }

            return result.Success
                ? (true, $"Java {version} 安装成功")
                : (false, "安装失败，请检查系统包管理器");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                $"install Microsoft.OpenJDK.{version} --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, $"Java {version} 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallMavenAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        if (os == "Linux")
        {
            var result = await ExecuteCommandAsync(
                "apt-get",
                "install -y maven",
                taskId,
                stepId,
                timeoutMs: 300000);

            if (!result.Success)
            {
                result = await ExecuteCommandAsync(
                    "yum",
                    "install -y maven",
                    taskId,
                    stepId,
                    timeoutMs: 300000);
            }

            return result.Success
                ? (true, "Maven 安装成功")
                : (false, "安装失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                "install Apache.Maven --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Maven 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallGradleAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        if (os == "Linux")
        {
            var result = await ExecuteCommandAsync(
                "apt-get",
                "install -y gradle",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Gradle 安装成功")
                : (false, "安装失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                "install Gradle.Gradle --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Gradle 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallNodeJsAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        version ??= "20";

        if (os == "Linux")
        {
            // 使用 NodeSource
            await SendLogAsync(taskId, stepId, "配置 NodeSource 仓库...");

            var setupResult = await ExecuteCommandAsync(
                "curl",
                $"-fsSL https://deb.nodesource.com/setup_{version}.x | bash -",
                taskId,
                stepId,
                timeoutMs: 120000);

            if (!setupResult.Success)
            {
                return (false, "配置仓库失败");
            }

            await SendLogAsync(taskId, stepId, "安装 Node.js...");

            var installResult = await ExecuteCommandAsync(
                "apt-get",
                "install -y nodejs",
                taskId,
                stepId,
                timeoutMs: 300000);

            return installResult.Success
                ? (true, $"Node.js {version} 安装成功")
                : (false, "安装失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                $"install OpenJS.NodeJS.LTS --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Node.js 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallPythonAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        version ??= "3.11";

        if (os == "Linux")
        {
            var result = await ExecuteCommandAsync(
                "apt-get",
                $"install -y python{version}",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, $"Python {version} 安装成功")
                : (false, "安装失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                $"install Python.Python.{version} --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, $"Python {version} 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallRustAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        if (os == "Linux" || os == "macOS")
        {
            await SendLogAsync(taskId, stepId, "下载 Rust 安装脚本...");

            var result = await ExecuteCommandAsync(
                "curl",
                "--proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Rust 安装成功")
                : (false, "安装失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                "install Rustlang.Rustup --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Rust 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    private async Task<(bool Success, string Message)> InstallGoAsync(
        string? version,
        string os,
        long? taskId,
        long? stepId)
    {
        version ??= "1.21";

        if (os == "Linux")
        {
            await SendLogAsync(taskId, stepId, $"下载 Go {version}...");

            var result = await ExecuteCommandAsync(
                "wget",
                $"https://go.dev/dl/go{version}.linux-amd64.tar.gz -O /tmp/go.tar.gz",
                taskId,
                stepId,
                timeoutMs: 120000);

            if (!result.Success)
            {
                return (false, "下载失败");
            }

            await ExecuteCommandAsync("rm", "-rf /usr/local/go", taskId, stepId);

            var extractResult = await ExecuteCommandAsync(
                "tar",
                "-C /usr/local -xzf /tmp/go.tar.gz",
                taskId,
                stepId);

            return extractResult.Success
                ? (true, $"Go {version} 安装成功，请确保 /usr/local/go/bin 在 PATH 中")
                : (false, "解压失败");
        }
        else if (os == "Windows")
        {
            var result = await ExecuteCommandAsync(
                "winget",
                "install GoLang.Go --silent --accept-package-agreements --accept-source-agreements",
                taskId,
                stepId,
                timeoutMs: 300000);

            return result.Success
                ? (true, "Go 安装成功")
                : (false, "安装失败");
        }

        return (false, $"不支持在 {os} 上自动安装");
    }

    #endregion

    #region 辅助方法

    private string GetOperatingSystem()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            return "Linux";
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return "Windows";
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return "macOS";
        return "Unknown";
    }

    private async Task<(bool Success, string Output)> ExecuteCommandAsync(
        string command,
        string arguments,
        long? taskId,
        long? stepId,
        int timeoutMs = 60000)
    {
        try
        {
            var startInfo = new ProcessStartInfo
            {
                FileName = command,
                Arguments = arguments,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            using var process = new Process { StartInfo = startInfo };
            var output = new StringBuilder();
            var error = new StringBuilder();

            process.OutputDataReceived += async (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                {
                    output.AppendLine(e.Data);
                    _logger.LogDebug("安装输出: {Line}", e.Data);
                    await SendLogAsync(taskId, stepId, e.Data);
                }
            };

            process.ErrorDataReceived += async (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                {
                    error.AppendLine(e.Data);
                    _logger.LogDebug("安装错误: {Line}", e.Data);
                    await SendLogAsync(taskId, stepId, e.Data, "Warning");
                }
            };

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            using var cts = new CancellationTokenSource(timeoutMs);
            await process.WaitForExitAsync(cts.Token);

            var result = output.Length > 0 ? output.ToString() : error.ToString();
            return (process.ExitCode == 0, result);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "命令执行失败: {Command} {Arguments}", command, arguments);
            return (false, ex.Message);
        }
    }

    private async Task SendLogAsync(long? taskId, long? stepId, string message, string logLevel = "Info")
    {
        if (_taskExecutor != null && taskId.HasValue && stepId.HasValue)
        {
            await _taskExecutor.SendLogAsync(taskId.Value, stepId.Value, message, logLevel);
        }
    }

    #endregion
}
